using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Net;

namespace Microsoft.Office.Project.EPMSync.Config.Library
{
    public class NetTraceEventArgs : EventArgs
    {
        public NetTraceEventArgs(string message)
        {
            msg = message;
        }
        private string msg;
        public string Message
        {
            get { return msg; }
        }
    }


    public class NetTraceReceiver : IDisposable
    {
        public event EventHandler<NetTraceEventArgs> RaiseNetTraceEvent;

        protected virtual void OnRaiseNetTraceEvent(NetTraceEventArgs e)
        {
            // Event will be null if there are no subscribers
            if (RaiseNetTraceEvent != null)
            {
                // Use the () operator to raise the event.
                RaiseNetTraceEvent(this, e);
            }
        }
 
        private ManualResetEvent _pause = new ManualResetEvent(false);
        Thread _workerThread;
        private bool _closing;

        public NetTraceReceiver()
        {
            Start();
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                _pause.Close();
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(true);
        }

        public void Start()
        {
            // Spawn thread to get updates on the control
            _workerThread = new Thread(new ThreadStart(UpdateMethod));
            _workerThread.Start();
            _pause.Set();
        }

        public void Stop()
        {
            _pause.Reset();
            Thread.Sleep(200);
            if (_workerThread != null)
                _workerThread.Abort();
            _pause.Set();
        }

        private void UpdateMethod()
        {

            UdpClient client = null;

            try
            {
                IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(TraceConsts.NetTraceIP), TraceConsts.NetTracePort);
                client = new UdpClient(endPoint);
                client.BeginReceive(new AsyncCallback(ReceiveCallback), client);

                do
                {
                    Thread.Sleep(50);
                    // Block if the service is paused or is shutting down.
                    _pause.WaitOne();
                } while (true);
            }
            catch (ThreadAbortException)
            {
                if (client != null)
                {
                    _closing = true;
                    client.Close();
                    Thread.Sleep(200);
                }
                Thread.ResetAbort();
            }
        }

        public void ReceiveCallback(IAsyncResult ar)
        {
            if (ar != null)
            {
                UdpClient client = ar.AsyncState as UdpClient;

                // Need to check if the worker thread closed, otherwise could be in a race condition and throw an exception
                if (!_closing)
                {
                    IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(TraceConsts.NetTraceIP), TraceConsts.NetTracePort);

                    Byte[] receiveBytes = client.EndReceive(ar, ref endPoint);
                    string receiveString = Encoding.ASCII.GetString(receiveBytes);

                    OnRaiseNetTraceEvent(new NetTraceEventArgs(receiveString));
                    client.BeginReceive(new AsyncCallback(ReceiveCallback), client);
                }
            }
        }

    }
}
